//
// UIScrollView+SVInfiniteScrolling.m
//
// Created by Sam Vermette on 23.04.12.
// Copyright (c) 2012 samvermette.com. All rights reserved.
//
// https://github.com/samvermette/SVPullToRefresh
//

#import <QuartzCore/QuartzCore.h>
#import "UIScrollView+SVInfiniteScrolling.h"
#import "PullTableView.h"

static CGFloat const SVInfiniteScrollingViewHeight = 50;

@interface SVInfiniteScrollingDotView : UIView
@property (nonatomic, strong) UIColor *arrowColor;
@end

@interface SVInfiniteScrollingView ()
@property (nonatomic, copy) void (^infiniteScrollingHandler)(void);
@property (nonatomic, strong) NSMutableArray *viewForState;
@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, readwrite) CGFloat originalBottomInset;
@property (nonatomic, assign) BOOL wasTriggeredByUser;
@property (nonatomic, assign) BOOL isObserving;
@property (strong, nonatomic) UIButton *loadMoreBtn;
@property (strong, nonatomic) UIView *loadingView;
- (void)resetScrollViewContentInset;
- (void)setScrollViewContentInsetForInfiniteScrolling;
- (void)setScrollViewContentInset:(UIEdgeInsets)insets;
@end

#pragma mark - UIScrollView (SVInfiniteScrollingView)
#import <objc/runtime.h>

static char UIScrollViewInfiniteScrollingView;
UIEdgeInsets scrollViewOriginalContentInsets;

@implementation UIScrollView (SVInfiniteScrolling)

@dynamic infiniteScrollingView;

- (void)addInfiniteScrollingWithActionHandler:(void (^)(void))actionHandler {
    if (!self.infiniteScrollingView) {
        SVInfiniteScrollingView *view = [[SVInfiniteScrollingView alloc] initWithFrame:CGRectMake(0, self.contentSize.height, self.bounds.size.width, SVInfiniteScrollingViewHeight)];
        view.infiniteScrollingHandler = actionHandler;
        view.scrollView = self;
        view.originalBottomInset = self.contentInset.bottom;
        self.infiniteScrollingView = view;
        self.showsInfiniteScrolling = YES;
        [self addSubview:view];
    }
}

- (void)setInfiniteScrollingView:(SVInfiniteScrollingView *)infiniteScrollingView {
    [self willChangeValueForKey:@"UIScrollViewInfiniteScrollingView"];
    objc_setAssociatedObject(self, &UIScrollViewInfiniteScrollingView, infiniteScrollingView, OBJC_ASSOCIATION_ASSIGN);
    [self didChangeValueForKey:@"UIScrollViewInfiniteScrollingView"];
}

- (SVInfiniteScrollingView *)infiniteScrollingView {
    return objc_getAssociatedObject(self, &UIScrollViewInfiniteScrollingView);
}

- (void)setShowsInfiniteScrolling:(BOOL)showsInfiniteScrolling {
    self.infiniteScrollingView.hidden = !showsInfiniteScrolling;
    if (!showsInfiniteScrolling) {
        if (self.infiniteScrollingView.isObserving) {
            [self removeObserver:self.infiniteScrollingView forKeyPath:@"contentOffset"];
            [self removeObserver:self.infiniteScrollingView forKeyPath:@"contentSize"];
            [self.infiniteScrollingView resetScrollViewContentInset];
            self.infiniteScrollingView.isObserving = NO;
        }
    } else {
        if (!self.infiniteScrollingView.isObserving) {
            [self addObserver:self.infiniteScrollingView forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
            [self addObserver:self.infiniteScrollingView forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
            [self.infiniteScrollingView setScrollViewContentInsetForInfiniteScrolling];
            self.infiniteScrollingView.isObserving = YES;
            [self.infiniteScrollingView setNeedsLayout];
            self.infiniteScrollingView.frame = CGRectMake(0, self.contentSize.height, self.infiniteScrollingView.bounds.size.width, SVInfiniteScrollingViewHeight);
        }
    }
}

- (BOOL)showsInfiniteScrolling {
    return !self.infiniteScrollingView.hidden;
}

@end


#pragma mark - SVInfiniteScrollingView


@implementation SVInfiniteScrollingView

// public properties
@synthesize infiniteScrollingHandler, activityIndicatorViewStyle;

@synthesize state = _state;
@synthesize scrollView = _scrollView;
@synthesize activityIndicatorView = _activityIndicatorView;

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        
        // default styling values
        self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        self.enabled = YES;
        [self doInit];
        self.state = SVInfiniteScrollingStateHidden;
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (void)doInit {
    self.loadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, SVInfiniteScrollingViewHeight)];
    self.loadMoreBtn = [[UIButton alloc] initWithFrame:_loadingView.frame];
    [self.loadMoreBtn setTitle:@"下拉查看更多" forState:UIControlStateNormal];
    [self.loadMoreBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    self.loadMoreBtn.titleLabel.font = [UIFont systemFontOfSize:14.f];
    [self.loadMoreBtn addTarget:self action:@selector(failRequestAndRetry) forControlEvents:UIControlEventTouchUpInside];
    
    UIActivityIndicatorView *indicator  = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    indicator.hidesWhenStopped = YES;
    UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(110, 0, 150, SVInfiniteScrollingViewHeight)];
    label1.text = @"加载中...";
    label1.font = [UIFont systemFontOfSize:14.f];
    label1.textColor = [UIColor whiteColor];
    label1.backgroundColor = [UIColor clearColor];
    CGPoint point = indicator.center;
    point.x = 95;
    point.y = SVInfiniteScrollingViewHeight / 2;
    indicator.center = point;
    self.activityIndicatorView = indicator;
    
    [_loadingView addSubview:indicator];
    [_loadingView addSubview:label1];

    [self addSubview:self.loadingView];
    [self addSubview:self.loadMoreBtn];
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (self.superview && newSuperview == nil) {
        UIScrollView *scrollView = (UIScrollView *)self.superview;
        if (scrollView.showsInfiniteScrolling) {
            if (self.isObserving) {
                [scrollView removeObserver:self forKeyPath:@"contentOffset"];
                [scrollView removeObserver:self forKeyPath:@"contentSize"];
                self.isObserving = NO;
            }
        }
    }
}

- (void)layoutSubviews {
    self.loadingView.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    self.loadMoreBtn.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
}

#pragma mark - Scroll View

- (void)resetScrollViewContentInset {
    UIEdgeInsets currentInsets = self.scrollView.contentInset;
    currentInsets.bottom = self.originalBottomInset;
    [self setScrollViewContentInset:currentInsets];
}

- (void)setScrollViewContentInsetForInfiniteScrolling {
    UIEdgeInsets currentInsets = self.scrollView.contentInset;
    currentInsets.bottom = self.originalBottomInset + SVInfiniteScrollingViewHeight;
    [self setScrollViewContentInset:currentInsets];
}

- (void)setScrollViewContentInset:(UIEdgeInsets)contentInset {
    self.scrollView.contentInset = contentInset;
}

#pragma mark - Observing

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (self.scrollView.contentOffset.y + self.scrollView.contentInset.top < 0) {
        return;
    }
    if ([keyPath isEqualToString:@"contentOffset"]) {
        if (self.scrollView.contentOffset.y == -self.scrollView.contentInset.top) {
            return;
        }
        [self scrollViewDidScroll:[[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]];
    }
    else if ([keyPath isEqualToString:@"contentSize"]) {
        if (self.state == SVInfiniteScrollingStateNoMore) {
            if (!self.hasNoInfiniteScrollingView) {
                self.hasNoInfiniteScrollingView = YES;
                [self resetScrollViewContentInset];
            }
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, 0, 0);
        } else {
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, self.scrollView.bounds.size.width, SVInfiniteScrollingViewHeight);
        }
        if (_mydelegate && [_mydelegate respondsToSelector:@selector(contentSizeHasChanged)]) {
            [_mydelegate contentSizeHasChanged];
        }
    }
}

- (void)scrollViewDidScroll:(CGPoint)contentOffset {
    if (contentOffset.y + self.scrollView.contentInset.top < 0) {
        return;
    }
    if (self.state != SVInfiniteScrollingStateLoading && self.enabled) {
        PullTableView *pull = (PullTableView *)self.scrollView;
        if (!pull.pullDelegate) {
            return;
        }
        CGFloat scrollViewContentHeight = self.scrollView.contentSize.height;
        CGFloat scrollOffsetThreshold = scrollViewContentHeight-self.scrollView.bounds.size.height;
        
        if (!self.scrollView.isDragging && contentOffset.y + self.scrollView.contentInset.top > scrollOffsetThreshold
            && self.state == SVInfiniteScrollingStateNormal) {
            self.state = SVInfiniteScrollingStateLoading;
        }
    }
}

#pragma mark - Getters


- (UIActivityIndicatorViewStyle)activityIndicatorViewStyle {
    return self.activityIndicatorView.activityIndicatorViewStyle;
}

#pragma mark - Setters

- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)viewStyle {
    self.activityIndicatorView.activityIndicatorViewStyle = viewStyle;
}

#pragma mark -

- (void)setState:(SVInfiniteScrollingState)newState {
    NSUInteger previousState = _state;
    if (_state == newState) return;
    [self layoutSubviews];

    switch (newState) {
        case SVInfiniteScrollingStateNoMore: {
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, 0, 0);
            self.loadingView.hidden = YES;
            self.enabled = NO;
            self.loadMoreBtn.userInteractionEnabled = NO;
            self.loadMoreBtn.hidden = YES;
            [self.activityIndicatorView stopAnimating];
            break;
        }
        case SVInfiniteScrollingStateNormal: {
            [self setScrollViewContentInsetForInfiniteScrolling];
             self.hasNoInfiniteScrollingView = NO;
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, self.scrollView.bounds.size.width, SVInfiniteScrollingViewHeight);
            self.hidden = NO;
            self.loadingView.hidden = YES;
            self.enabled = YES;
            [self.loadMoreBtn setTitle:@"下拉查看更多" forState:UIControlStateNormal];
            self.loadMoreBtn.userInteractionEnabled = NO;
            self.loadMoreBtn.hidden = NO;
            [self.activityIndicatorView stopAnimating];
            break;
        }
        case SVInfiniteScrollingStateLoading: {
            [self setScrollViewContentInsetForInfiniteScrolling];
            self.hasNoInfiniteScrollingView = NO;
            self.hidden = NO;
            self.loadingView.hidden = NO;
            self.enabled = YES;
            self.loadMoreBtn.hidden = YES;
            [self.activityIndicatorView startAnimating];
            break;
        }
        case SVInfiniteScrollingStateFailAndHidden: {
            [self setScrollViewContentInsetForInfiniteScrolling];
            self.hasNoInfiniteScrollingView = NO;
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, 0, 0);
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, self.scrollView.bounds.size.width, SVInfiniteScrollingViewHeight);
            self.hidden = NO;
            self.loadingView.hidden = YES;
            self.enabled = NO;
            self.loadMoreBtn.userInteractionEnabled = YES;
            self.loadMoreBtn.hidden = NO;
            [self.loadMoreBtn setTitle:@"加载失败，点击重试" forState:UIControlStateNormal];
            [self.activityIndicatorView stopAnimating];
            break;
        }
        case SVInfiniteScrollingStateHidden: {
            [self setScrollViewContentInsetForInfiniteScrolling];
            self.hasNoInfiniteScrollingView = NO;
            self.frame = CGRectMake(0, self.scrollView.contentSize.height, 0, 0);
            self.loadingView.hidden = YES;
            self.enabled = NO;
            self.loadMoreBtn.userInteractionEnabled = NO;
            self.loadMoreBtn.hidden = YES;
            [self.activityIndicatorView stopAnimating];
            break;
        }
    }
    _state = newState;
    if ((previousState == SVInfiniteScrollingStateNormal || previousState == SVInfiniteScrollingStateFailAndHidden) && newState == SVInfiniteScrollingStateLoading && self.infiniteScrollingHandler && self.enabled) {
        self.infiniteScrollingHandler();
    }
}

- (void)failRequestAndRetry {
    self.state = SVInfiniteScrollingStateLoading;
}

@end
